package com.grm.workflow.service.impl;

import com.grm.common.entity.PageResult;
import com.grm.common.utils.JwtUtil;
import com.grm.sys.mapper.SysUserMapper;
import com.grm.sys.model.SysUser;
import com.grm.workflow.request.my.todo.WfMyToDoQueryParam;
import com.grm.workflow.response.WfMyToDoResponse;
import com.grm.workflow.service.WfMyToDoService;
import com.grm.workflow.utils.TaskUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WfMyToDoServiceImpl implements WfMyToDoService {
    @Autowired
    private RepositoryService repositoryService;
    @Resource
    private HistoryService historyService;
    @Autowired
    private JwtUtil jwtUtil;
    @Resource
    private TaskService taskService;
    @Autowired
    private TaskUtils taskUtils;
    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public PageResult<WfMyToDoResponse> querySelective(Integer pageNum, Integer pageSize, WfMyToDoQueryParam queryParam) {
        String loginUserIdStr = String.valueOf(jwtUtil.getUserId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .active()
                .includeProcessVariables()
                .taskCandidateOrAssigned(loginUserIdStr)
                .taskCandidateGroupIn(taskUtils.getCandidateGroup())
                .orderByTaskCreateTime().desc();
        // 应用查询条件
        buildQueryParam(queryParam, taskQuery);
        long pageTotal = taskQuery.count();
        if (pageTotal == 0) {
            return new PageResult<>(List.of(), 0L);
        }
        List<Task> taskList = taskQuery.listPage((pageNum - 1) * pageSize, pageSize);
        List<WfMyToDoResponse> toDoResponseList = new ArrayList<>();
        // 批量操作
        // 提取所有需要的流程定义 ID 和流程实例 ID
        Set<String> procDefIds = new HashSet<>();
        Set<String> procInsIds = new HashSet<>();
        for (Task task : taskList) {
            procDefIds.add(task.getProcessDefinitionId());
            procInsIds.add(task.getProcessInstanceId());
        }
        // 批量查询流程定义（Map key为procDefId）
        Map<String, ProcessDefinition> processDefinitionMap = repositoryService.createProcessDefinitionQuery()
                .processDefinitionIds(procDefIds)
                .list()
                .stream()
                .collect(Collectors.toMap(ProcessDefinition::getId, Function.identity()));
        // 批量查询流程实例发起人
        List<HistoricProcessInstance> historicProcessInstanceList = historyService.createHistoricProcessInstanceQuery()
                .processInstanceIds(procInsIds)
                .list();
        List<Long> startUserIds = historicProcessInstanceList.stream().map(HistoricProcessInstance::getStartUserId).map(Long::parseLong).distinct().collect(Collectors.toList());
        List<SysUser> startUserList = sysUserMapper.queryByIds(startUserIds);
        // Map key为procInsId
        Map<String, HistoricProcessInstance> historicProcessInstanceMap = historicProcessInstanceList.stream().collect(Collectors.toMap(HistoricProcessInstance::getId, Function.identity()));
        for (Task task : taskList) {
            WfMyToDoResponse toDoResponse = new WfMyToDoResponse();
            // Task转WfMyToDoResponse
            // 当前流程信息
            toDoResponse.setTaskId(task.getId());
            toDoResponse.setCreateTime(task.getCreateTime());
            toDoResponse.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = processDefinitionMap.get(task.getProcessDefinitionId());
            toDoResponse.setProcDefName(pd.getName());
            toDoResponse.setProcDefVersion(pd.getVersion());
            toDoResponse.setProcInsId(task.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            // 查找对应的SysUser
            SysUser sysUser = startUserList.stream()
                    .filter(u -> u.getId().equals(userId))
                    .findFirst()
                    .orElse(null);
            if (sysUser != null) {
                toDoResponse.setStartUserId(userId);
                toDoResponse.setStartUserName(sysUser.getUsername());
                toDoResponse.setStartUserRealName(sysUser.getRealName());
            }
            toDoResponseList.add(toDoResponse);
        }
        return new PageResult<>(toDoResponseList, pageTotal);
    }

    private void buildQueryParam(WfMyToDoQueryParam queryParam, TaskQuery query) {
        if (StringUtils.isNotBlank(queryParam.getProcessName())) {
            query.processDefinitionName(queryParam.getProcessName());
        }
    }
}
